# plugs/upgrade.py
#
#

""" upgrade command .. determine on svn update's output if plugs can 
    be reloaded or that the bot has to be rebooted
"""

__copyright__ = 'this file is in the public domain'

from gozerbot.fleet import fleet
from gozerbot.plugins import plugins
from gozerbot.commands import cmnds
from gozerbot.examples import examples
from gozerbot.generic import reboot, gozerpopennocheck, gozerpopen
from gozerbot.plughelp import plughelp
from gozerbot.config import config, gethgrev, getsvnrev
import os, os.path, time

plughelp.add('upgrade', "do a mercurial hg pull -u  and see if we need to \
reboot .. if only plugins are updated we don't need to reboot because we \
can reload them")

def pluglistreload(pluglist):
    """ reload list of plugins """
    failed = []
    for what in pluglist:
        splitted = what[:-3].split('/')
        mod = '.'.join(splitted[:-1])
        plug  = splitted[-1]
        # reload the plugin
        try:
            plugins.reload(mod, plug)
        except Exception, ex:
            failed.append(what)
    return failed

def handle_hgupgrade(bot, ievent):
    """ upgrade .. do a mercurial pull -u .. see if we need to reboot \
        otherwise reload plugins """
    startrev = gethgrev()
    url = None
    if ievent.rest:
        url = ievent.rest
    else:
        url = config['upgradeurl']
    if url:
        if url.startswith('-'):
            ievent.reply('i need a url')
            return
        args = ['hg', 'pull', '-u', url]
    else:
        args = ['hg', 'pull', '-u']
    try:
        proces = gozerpopennocheck(args)
    except Exception, ex:
        ievent.reply('error running popen: %s' % str(ex))
        return
    nochange = 0
    lines = proces.fromchild.readlines()
    for i in lines:
        if 'abort: error:' in i:
            ievent.reply('failed to update ==>  %s' % i)
            return
        if 'no changes' in i:
            nochange = 1
    if nochange:
        ievent.reply('no changes')
        return
    else:
        ievent.reply(' .. '.join(lines))
    rev = gethgrev()
    ievent.reply('revision is %s' % rev)
    args = ['hg', 'diff', '-r%s' % startrev]
    try:
        proces = gozerpopennocheck(args)
    except Exception, ex:
        ievent.reply('error running popen: %s' % str(ex))
        return
    data = proces.fromchild.readlines()
    if proces.wait():
        ievent.reply("can't run hg diff")
        return
    files = []
    plugs = []
    dbplugs = []
    needreboot = 0
    for i in data:
        if i.startswith('+++') or i.startswith('---'):
            filename = '/'.join(i.split()[1].split('/')[1:])
            if filename == 'dev/null':
                continue
            if filename not in files:
                files.append(filename)
            if not filename.endswith('.py'):
                continue
            if filename.startswith('gozerbot'): 
                needreboot = 1
            elif filename.find('dbplugs') != -1:
                if not config['dbenable']:
                    continue
                if filename not in dbplugs:
                    dbplugs.append(filename)
            elif filename.find('plugs') != -1:
                if filename not in plugs:
                    plugs.append(filename)
    ievent.reply('files: ' + ' '.join(files))
    summary = []
    args = ['hg', 'log', '-r%s:%s' % (rev, startrev+1)]
    try:
        proces = gozerpopennocheck(args)
    except Exception, ex:
        ievent.reply('error running popen: %s' % str(ex))
        return
    data = proces.fromchild.readlines()
    if not proces.wait():
        for i in data:
            if i.startswith('summary:'):
                summary.append(i.split('summary:')[1].strip())
        ievent.reply("summaries: %s" % ' .. '.join(summary))
    if needreboot:
        ievent.reply('need reboot')
        time.sleep(1)
        try:
            plugins.exit()
            fleet.exitall()
        finally:
            time.sleep(1)
            reboot()
    config.load()
    if not plugs and not dbplugs:
        ievent.reply('nothing to reload')
        return
    ievent.reply("reloading %s" %  " .. ".join(dbplugs + plugs))
    failed = pluglistreload(plugs)
    if config['dbenable']:
        failed += pluglistreload(dbplugs)
    if failed:
        ievent.reply("failed to reload %s" % ' .. '.join(failed))
        return
    else:
        ievent.reply('done')

cmnds.add('upgrade-hg', handle_hgupgrade, 'OPER')
examples.add('upgrade-hg', 'do a mercurial upgrade', 'upgrade-hg')

def handle_svnupgrade(bot, ievent):
    """ do a svn update and check if we have to reboot or that plugs reload
        is enough
    """
    args = ['svn', 'update']
    try:
        proces = gozerpopen(args)
    except Exception, ex:
        ievent.reply('error running popen: %s' % str(ex))
        return
    data = proces.fromchild.readlines()
    if proces.wait():
        ievent.reply('error running svn update')
        return
    plugs = []
    dbplugs = []
    needreboot = 0
    res = []
    for line in data:
        res.append(line.strip())
    if res:
        ievent.reply(" .. ".join(res))
    # see if we need to reboot and if not what plugins need to be reloaded
    for line in res:
        try:
            (svnaction, filename) = line.split()
        except ValueError:
            continue
        if svnaction == 'D':
            continue
        if filename.startswith('gozerbot'): 
            needreboot = 1
            break
        elif filename.find('dbplugs') != -1:
            if not config['dbenable']:
                continue
            if filename not in dbplugs:
                dbplugs.append(filename)
        elif filename.find('plugs') != -1:
            if filename not in plugs:
                plugs.append(filename)
    if needreboot:
        ievent.reply('need reboot')
        try:
            plugins.exit()
            fleet.exitall()
        finally:
            time.sleep(1)
            reboot()
    if not plugs and not dbplugs:
            ievent.reply('nothing to reload')
            return
    ievent.reply("reloading %s" %  " .. ".join(dbplugs + plugs))
    failed = pluglistreload(plugs)
    if config['dbenable']:
        failed += pluglistreload(dbplugs)
    if failed:
        ievent.reply("failed to reload %s" % ' .. '.join(failed))
        return
    else:
        ievent.reply('done')

cmnds.add('upgrade-svn', handle_svnupgrade, 'OPER')
examples.add('upgrade-svn', 'upgrade the bot with svn', 'upgrade-svn')

def handle_upgrade(bot, ievent):
    if os.path.isdir('.hg'):
        handle_hgupgrade(bot, ievent)
        return
    if os.path.isdir('.svn'):
        handle_svnupgrade(bot, ievent)
        return
    ievent.reply('i need a svn or mercurial repository for upgrade to work')
    
cmnds.add('upgrade', handle_upgrade, 'OPER')
examples.add('upgrade', 'do a svn or mercurial upgrade', 'upgrade')
